package com.gitee.webdav.monitor;

import cn.hutool.core.date.BetweenFormatter;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.unit.DataSizeUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.system.RuntimeInfo;
import cn.hutool.system.SystemUtil;
import cn.hutool.system.oshi.CpuInfo;
import cn.hutool.system.oshi.OshiUtil;
import com.gitee.webdav.HomeStarter;
import com.gitee.webdav.kernel.Remark;
import lombok.Data;
import lombok.experimental.Accessors;
import oshi.hardware.CentralProcessor;
import oshi.hardware.GlobalMemory;

import java.math.RoundingMode;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @author hongda.li@hand-china.com
 */
@Data
@Accessors(chain = true)
@Remark("系统信息")
public class MonitorInfo {
    private static final String EXCLUDE_SYSTEM = "/System";
    private static final String EXCLUDE_PRIVATE = "/private";

    @Remark("获取当前系统快照")
    public static MonitorInfo snapshot() {
        @Remark("采样结果")
        CpuInfo cpuInfo = OshiUtil.getCpuInfo();
        @Remark("CPU")
        CentralProcessor processor = OshiUtil.getProcessor();

        MonitorInfo info = new MonitorInfo();
        info.setCpuName(processor.getProcessorIdentifier().getName());
        info.setCpuUsage(NumberUtil.formatPercent(NumberUtil.div(100 - cpuInfo.getFree(), 100, 2, RoundingMode.HALF_DOWN), 0));

        @Remark("内存")
        GlobalMemory memory = OshiUtil.getMemory();
        info.setMemoryTotal(DataSizeUtil.format(memory.getTotal()));
        info.setMemoryUsed(DataSizeUtil.format(memory.getTotal() - memory.getAvailable()));
        info.setMemoryUsage(NumberUtil.formatPercent(NumberUtil.div((float) memory.getTotal() - memory.getAvailable(), memory.getTotal(), 2, RoundingMode.HALF_DOWN), 0));

        @Remark("JVM")
        RuntimeInfo jvm = SystemUtil.getRuntimeInfo();
        info.setJvmTotal(DataSizeUtil.format(jvm.getMaxMemory()));
        info.setJvmUsed(DataSizeUtil.format(jvm.getTotalMemory()));
        info.setJvmUsage(NumberUtil.formatPercent(NumberUtil.div(jvm.getTotalMemory(), jvm.getMaxMemory(), 2, RoundingMode.HALF_DOWN), 0));

        @Remark("运行时间")
        long millis = HomeStarter.getRuntime();
        info.setRunDay(DateUtil.betweenDay(new Date(millis), new Date(System.currentTimeMillis()), false));
        info.setRuntimeInfo(DateUtil.formatBetween(System.currentTimeMillis() - millis, BetweenFormatter.Level.SECOND));

        info.setDiskInfoList(OshiUtil.getOs()
                .getFileSystem()
                .getFileStores()
                .stream()
                .filter(store -> !store.getMount().startsWith(EXCLUDE_SYSTEM) && !store.getMount().startsWith(EXCLUDE_PRIVATE))
                .map(store -> {
                    long totalSpace = store.getTotalSpace();
                    if (totalSpace <= 0) {
                        return null;
                    }
                    @Remark("磁盘信息")
                    DiskInfo diskInfo = new DiskInfo();
                    diskInfo.setName(store.getName());
                    diskInfo.setPath(store.getMount());
                    diskInfo.setSize(DataSizeUtil.format(totalSpace));
                    diskInfo.setFree(DataSizeUtil.format(store.getUsableSpace()));
                    diskInfo.setUsed(DataSizeUtil.format(totalSpace - store.getUsableSpace()));
                    diskInfo.setUsage(NumberUtil.formatPercent(NumberUtil.div((float) totalSpace - store.getUsableSpace(), totalSpace, 2, RoundingMode.HALF_DOWN), 0));
                    return diskInfo;
                })
                .filter(Objects::nonNull)
                .toList());
        return info;
    }

    @Remark("CPU型号")
    private String cpuName;

    @Remark("CPU已使用量，百分比")
    private String cpuUsage;

    @Remark("内存总容量")
    private String memoryTotal;

    @Remark("内存已使用量")
    private String memoryUsed;

    @Remark("内存已使用量，百分比")
    private String memoryUsage;

    @Remark("JVM总容量")
    private String jvmTotal;

    @Remark("JVM已使用量")
    private String jvmUsed;

    @Remark("JVM已使用量，百分比")
    private String jvmUsage;

    @Remark("运行天数")
    private Long runDay;

    @Remark("运行具体时间")
    private String runtimeInfo;

    @Remark("硬盘信息")
    private List<DiskInfo> diskInfoList;

    @Data
    @Accessors(chain = true)
    @Remark("硬盘信息")
    public static final class DiskInfo {

        @Remark("名称")
        private String name;

        @Remark("总容量")
        private String size;

        @Remark("挂载路径")
        private String path;

        @Remark("已使用容量")
        private String used;

        @Remark("剩余容量")
        private String free;

        @Remark("利用率，百分比")
        private String usage;
    }
}
